import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.*;
import javafx.stage.FileChooser;
import javafx.stage.Stage;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class PuzzleGame extends Application {
    private Button[][] buttons;
    private int[][] puzzle;
    private int emptyRow;
    private int emptyCol;
    private long startTime;
    private int moveCount = 0;
    private boolean gameStarted = false;
    private Label timeLabel = new Label("时间: 0秒");
    private Label moveLabel = new Label("步数: 0");
    private Button startButton = new Button("开始游戏");
    private Button endButton = new Button("结束游戏");
    private Button switchDisplayButton = new Button("切换到图片"); // 切换显示模式按钮
    private MenuBar menuBar = new MenuBar();
    private int gridSize = 3; // 默认难度为3x3
    private Image originalImage; // 原始图片
    private Image[] puzzleImages; // 切分后的图片数组
    private boolean displayModeIsImage = false; // false=数字, true=图片

    @Override
    public void start(Stage primaryStage) {
        // 创建菜单栏
        Menu difficultyMenu = new Menu("难度");
        ToggleGroup difficultyGroup = new ToggleGroup();
        
        // 添加难度选项3-9
        for (int i = 3; i <= 9; i++) {
            RadioMenuItem item = new RadioMenuItem(i + "x" + i);
            item.setToggleGroup(difficultyGroup);
            if (i == gridSize) {
                item.setSelected(true);
            }
            final int level = i;
            item.setOnAction(e -> changeDifficulty(level));
            difficultyMenu.getItems().add(item);
        }
        
        // 添加图片菜单
        Menu imageMenu = new Menu("图片");
        MenuItem loadImgItem = new MenuItem("加载图片");
        loadImgItem.setOnAction(e -> loadImage());
        imageMenu.getItems().add(loadImgItem);
        
        // 添加游戏菜单
        Menu gameMenu = new Menu("游戏");
        MenuItem startGameItem = new MenuItem("开始游戏");
        startGameItem.setOnAction(e -> startGame());
        MenuItem endGameItem = new MenuItem("结束游戏");
        endGameItem.setOnAction(e -> endGame());
        MenuItem exitItem = new MenuItem("退出");
        exitItem.setOnAction(e -> primaryStage.close());
        gameMenu.getItems().addAll(startGameItem, endGameItem, new SeparatorMenuItem(), exitItem);
        
        // 添加帮助菜单
        Menu helpMenu = new Menu("帮助");
        MenuItem aboutItem = new MenuItem("关于");
        aboutItem.setOnAction(e -> showAboutDialog());
        helpMenu.getItems().add(aboutItem);
        
        menuBar.getMenus().addAll(gameMenu, difficultyMenu, imageMenu, helpMenu);

        // 创建主布局容器
        BorderPane root = new BorderPane();
        root.setTop(menuBar);
        
        // 创建中心游戏区域
        VBox centerBox = new VBox(5); // 减小间距
        centerBox.setAlignment(Pos.CENTER);
        centerBox.setPadding(new Insets(10)); // 减小内边距

        // 创建网格面板
        GridPane gridPane = new GridPane();
        gridPane.setAlignment(Pos.CENTER);
        gridPane.setHgap(2); // 减小水平间隙
        gridPane.setVgap(2); // 减小垂直间隙

        // 初始化按钮数组
        initializeGameGrid(gridSize);

        // 初始化按钮
        for (int row = 0; row < gridSize; row++) {
            for (int col = 0; col < gridSize; col++) {
                Button button = new Button();
                // 设置固定尺寸800x600的网格区域
                double buttonSizeWidth = 800.0 / gridSize;
                double buttonSizeHeight = 600.0 / gridSize;
                button.setPrefSize(buttonSizeWidth, buttonSizeHeight);
                button.setStyle("-fx-font-size: " + Math.max(12, 30/gridSize) + "px;");
                
                final int r = row;
                final int c = col;
                button.setOnAction(e -> handleButtonClick(r, c));
                
                buttons[row][col] = button;
                gridPane.add(button, col, row);
            }
        }

        // 初始化拼图
        initializePuzzle();

        // 创建控制面板
        HBox controlPanel = new HBox(5); // 减小间距
        controlPanel.setAlignment(Pos.CENTER);
        
        startButton.setOnAction(e -> startGame());
        endButton.setOnAction(e -> endGame());
        endButton.setDisable(true);
        switchDisplayButton.setOnAction(e -> switchDisplayMode()); // 设置切换显示模式按钮事件
        
        controlPanel.getChildren().addAll(startButton, endButton, switchDisplayButton, timeLabel, moveLabel);

        centerBox.getChildren().addAll(gridPane, controlPanel);
        root.setCenter(centerBox);

        Scene scene = new Scene(root, 900, 700); // 调整窗口大小以适应800x600的网格区域
        primaryStage.setTitle("拼图游戏");
        primaryStage.setScene(scene);
        
        // 尝试加载默认图片
        loadDefaultImage();
        
        primaryStage.show();
    }

    // 显示关于对话框
    private void showAboutDialog() {
        Alert alert = new Alert(Alert.AlertType.INFORMATION);
        alert.setTitle("关于");
        alert.setHeaderText("拼图游戏 v1.0");
        alert.setContentText("这是一个使用JavaFX开发的拼图游戏。\n\n"
                + "功能特点：\n"
                + "- 支持3x3到9x9多种难度\n"
                + "- 可以使用数字或图片进行游戏\n"
                + "- 支持自定义图片\n"
                + "- 统计游戏时间和步数\n\n"
                + "开发者：Assistant");
        alert.showAndWait();
    }

    // 加载默认图片
    private void loadDefaultImage() {
        // 首先尝试从根目录加载
        File imageFile = new File("01.jpg");
        if (!imageFile.exists()) {
            // 如果根目录没有，则尝试从img文件夹加载
            imageFile = new File("img/01.jpg");
        }
        
        if (imageFile.exists()) {
            try {
                BufferedImage bufferedImage = ImageIO.read(imageFile);
                originalImage = SwingFXUtils.toFXImage(bufferedImage, null);
                // 如果游戏未进行中，更新显示
                if (!gameStarted) {
                    createPuzzleImages();
                    updateAllButtons();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    // 加载图片
    private void loadImage() {
        FileChooser fileChooser = new FileChooser();
        fileChooser.setTitle("选择图片");
        fileChooser.getExtensionFilters().addAll(
            new FileChooser.ExtensionFilter("图片文件", "*.png", "*.jpg", "*.jpeg", "*.gif", "*.bmp")
        );
        
        File selectedFile = fileChooser.showOpenDialog(menuBar.getScene().getWindow());
        if (selectedFile != null) {
            try {
                BufferedImage bufferedImage = ImageIO.read(selectedFile);
                originalImage = SwingFXUtils.toFXImage(bufferedImage, null);
                // 如果游戏未进行中，更新显示
                if (!gameStarted) {
                    createPuzzleImages();
                    updateAllButtons();
                }
            } catch (IOException e) {
                Alert alert = new Alert(Alert.AlertType.ERROR);
                alert.setTitle("错误");
                alert.setHeaderText(null);
                alert.setContentText("无法加载图片: " + e.getMessage());
                alert.showAndWait();
            }
        }
    }

    // 创建拼图图片
    private void createPuzzleImages() {
        if (originalImage == null) return;
        
        puzzleImages = new Image[gridSize * gridSize];
        double imgWidth = originalImage.getWidth();
        double imgHeight = originalImage.getHeight();
        
        // 计算每个子图片的尺寸
        double pieceWidth = imgWidth / gridSize;
        double pieceHeight = imgHeight / gridSize;
        
        for (int row = 0; row < gridSize; row++) {
            for (int col = 0; col < gridSize; col++) {
                int index = row * gridSize + col;
                if (index < gridSize * gridSize - 1) { // 最后一个位置是空白
                    // 从原始图片中截取子图片
                    WritableImage pieceImage = new WritableImage((int)pieceWidth, (int)pieceHeight);
                    pieceImage.getPixelWriter().setPixels(0, 0, (int)pieceWidth, (int)pieceHeight,
                            originalImage.getPixelReader(), (int)(col * pieceWidth), (int)(row * pieceHeight));
                    puzzleImages[index] = pieceImage;
                } else {
                    // 创建空白图片
                    puzzleImages[index] = null;
                }
            }
        }
    }

    // 根据网格大小计算按钮尺寸
    private double calculateButtonSize(int gridSize) {
        // 基础尺寸根据网格大小调整
        if (gridSize <= 3) return 80;
        if (gridSize <= 5) return 60;
        if (gridSize <= 7) return 45;
        return 35;
    }

    // 根据网格大小计算窗口尺寸
    private double calculateWindowSize(int gridSize) {
        double baseSize = 100 + gridSize * calculateButtonSize(gridSize);
        return Math.max(baseSize, 300); // 最小窗口尺寸为300
    }

    // 初始化游戏网格
    private void initializeGameGrid(int size) {
        buttons = new Button[size][size];
        puzzle = new int[size][size];
    }

    // 初始化拼图
    private void initializePuzzle() {
        int num = 1;
        for (int row = 0; row < gridSize; row++) {
            for (int col = 0; col < gridSize; col++) {
                puzzle[row][col] = num;
                num++;
            }
        }
        emptyRow = gridSize - 1;
        emptyCol = gridSize - 1;
        
        // 创建拼图图片
        createPuzzleImages();
        // 更新按钮显示
        updateAllButtons();
    }

    // 更新所有按钮显示
    private void updateAllButtons() {
        for (int row = 0; row < gridSize; row++) {
            for (int col = 0; col < gridSize; col++) {
                updateButton(row, col);
            }
        }
    }

    // 改变难度
    private void changeDifficulty(int level) {
        if (gameStarted) {
            Alert alert = new Alert(Alert.AlertType.WARNING);
            alert.setTitle("警告");
            alert.setHeaderText(null);
            alert.setContentText("游戏进行中，请先完成当前游戏再更改难度！");
            alert.showAndWait();
            return;
        }
        
        gridSize = level;
        initializeGameGrid(gridSize);
        restartGame();
    }

    // 重新开始游戏
    private void restartGame() {
        BorderPane root = (BorderPane) menuBar.getParent();
        VBox centerBox = (VBox) root.getCenter();
        GridPane gridPane = (GridPane) centerBox.getChildren().get(0);
        
        // 清除旧的按钮
        gridPane.getChildren().clear();
        
        // 重新创建按钮
        for (int row = 0; row < gridSize; row++) {
            for (int col = 0; col < gridSize; col++) {
                Button button = new Button();
                // 设置固定尺寸800x600的网格区域
                double buttonSizeWidth = 800.0 / gridSize;
                double buttonSizeHeight = 600.0 / gridSize;
                button.setPrefSize(buttonSizeWidth, buttonSizeHeight);
                button.setStyle("-fx-font-size: " + Math.max(12, 30/gridSize) + "px;");
                
                final int r = row;
                final int c = col;
                button.setOnAction(e -> handleButtonClick(r, c));
                
                buttons[row][col] = button;
                gridPane.add(button, col, row);
            }
        }
        
        initializePuzzle();
        
        // 调整窗口大小 - 保持固定大小
        Scene scene = menuBar.getScene();
        Stage stage = (Stage) scene.getWindow();
        stage.setWidth(900);
        stage.setHeight(700);
        // 防止窗口大小变化，强制重新设置
        stage.sizeToScene();
    }

    // 开始游戏
    private void startGame() {
        gameStarted = true;
        moveCount = 0;
        startTime = System.currentTimeMillis();
        updateMoveCount();
        timeLabel.setText("时间: 0秒");
        
        // 启用结束游戏按钮
        endButton.setDisable(false);
        
        // 打乱拼图
        shufflePuzzle();
        
        // 启动计时器
        startTimer();
    }

    // 结束游戏
    private void endGame() {
        if (!gameStarted) return;
        
        gameStarted = false;
        timeLabel.setText("游戏已结束");
        moveLabel.setText("步数: " + moveCount);
        
        // 禁用结束游戏按钮
        endButton.setDisable(true);
        
        // 弹出提示框
        Alert alert = new Alert(Alert.AlertType.INFORMATION);
        alert.setTitle("游戏结束");
        alert.setHeaderText(null);
        alert.setContentText("你已结束游戏！");
        alert.showAndWait();
    }

    // 切换显示模式
    private void switchDisplayMode() {
        displayModeIsImage = !displayModeIsImage;
        if (displayModeIsImage) {
            switchDisplayButton.setText("切换到数字");
        } else {
            switchDisplayButton.setText("切换到图片");
        }
        updateAllButtons();
    }

    // 打乱拼图
    private void shufflePuzzle() {
        // 创建一个可移动的数字列表
        for (int i = 0; i < 1000; i++) {
            // 找到可以移动的相邻位置
            List<int[]> neighbors = getNeighbors(emptyRow, emptyCol);
            if (!neighbors.isEmpty()) {
                // 随机选择一个相邻位置
                int[] randomNeighbor = neighbors.get((int) (Math.random() * neighbors.size()));
                int row = randomNeighbor[0];
                int col = randomNeighbor[1];
                
                // 交换空位置和选中位置
                swapTiles(emptyRow, emptyCol, row, col);
                emptyRow = row;
                emptyCol = col;
            }
        }
    }

    // 获取相邻位置
    private List<int[]> getNeighbors(int row, int col) {
        List<int[]> neighbors = new ArrayList<>();
        int[][] directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; // 上下左右
        
        for (int[] dir : directions) {
            int newRow = row + dir[0];
            int newCol = col + dir[1];
            
            if (newRow >= 0 && newRow < gridSize && newCol >= 0 && newCol < gridSize) {
                neighbors.add(new int[]{newRow, newCol});
            }
        }
        
        return neighbors;
    }

    // 交换两个位置的数字
    private void swapTiles(int r1, int c1, int r2, int c2) {
        int temp = puzzle[r1][c1];
        puzzle[r1][c1] = puzzle[r2][c2];
        puzzle[r2][c2] = temp;
        
        updateButton(r1, c1);
        updateButton(r2, c2);
    }

    // 更新按钮显示
    private void updateButton(int row, int col) {
        int value = puzzle[row][col];
        Button button = buttons[row][col];
        
        if (value == gridSize * gridSize) {
            // 空白位置
            button.setText("");
            button.setGraphic(null);
            button.setStyle("-fx-background-color: white;");
        } else {
            if (displayModeIsImage && puzzleImages != null && puzzleImages[value - 1] != null) {
                // 显示图片
                ImageView imageView = new ImageView(puzzleImages[value - 1]);
                // 获取按钮的实际尺寸
                double buttonWidth = button.getWidth();
                double buttonHeight = button.getHeight();
                
                // 如果按钮尺寸还没确定，使用预设尺寸
                if (buttonWidth <= 0 || buttonHeight <= 0) {
                    buttonWidth = 800.0 / gridSize;
                    buttonHeight = 600.0 / gridSize;
                }
                
                // 设置图片适应按钮大小，消除空白
                imageView.setFitWidth(buttonWidth);
                imageView.setFitHeight(buttonHeight);
                imageView.setPreserveRatio(false); // 不保持比例，填满整个区域
                imageView.setSmooth(true);
                button.setGraphic(imageView);
                button.setText("");
                button.setStyle("-fx-padding: 0; -fx-background-color: white;"); // 移除按钮内边距
            } else {
                // 显示数字
                button.setGraphic(null);
                button.setText(String.valueOf(value));
                button.setStyle("-fx-font-size: " + Math.max(12, 30/gridSize) + "px; -fx-padding: 0;"); // 移除内边距
            }
        }
    }

    // 处理按钮点击
    private void handleButtonClick(int row, int col) {
        if (!gameStarted) return;
        
        // 检查点击的按钮是否与空位置相邻
        if (isAdjacent(row, col, emptyRow, emptyCol)) {
            // 移动数字到空位置
            swapTiles(row, col, emptyRow, emptyCol);
            emptyRow = row;
            emptyCol = col;
            
            moveCount++;
            updateMoveCount();
            
            // 检查游戏是否完成
            if (isPuzzleSolved()) {
                gameStarted = false;
                long endTime = System.currentTimeMillis();
                long timeElapsed = (endTime - startTime) / 1000;
                timeLabel.setText("时间: " + timeElapsed + "秒");
                moveLabel.setText("恭喜完成! 步数: " + moveCount);
                
                // 禁用结束游戏按钮
                endButton.setDisable(true);
            }
        }
    }

    // 检查两个位置是否相邻
    private boolean isAdjacent(int r1, int c1, int r2, int c2) {
        return (Math.abs(r1 - r2) == 1 && c1 == c2) || 
               (Math.abs(c1 - c2) == 1 && r1 == r2);
    }

    // 检查拼图是否已解决
    private boolean isPuzzleSolved() {
        int expected = 1;
        for (int row = 0; row < gridSize; row++) {
            for (int col = 0; col < gridSize; col++) {
                if (row == gridSize - 1 && col == gridSize - 1) {
                    // 最后一个位置应该是空的（最大数字）
                    if (puzzle[row][col] != gridSize * gridSize) return false;
                } else {
                    if (puzzle[row][col] != expected) return false;
                    expected++;
                }
            }
        }
        return true;
    }

    // 更新步数显示
    private void updateMoveCount() {
        moveLabel.setText("步数: " + moveCount);
    }

    // 启动计时器
    private void startTimer() {
        new Thread(() -> {
            while (gameStarted) {
                try {
                    Thread.sleep(1000);
                    if (gameStarted) {
                        long timeElapsed = (System.currentTimeMillis() - startTime) / 1000;
                        final long finalTime = timeElapsed;
                        javafx.application.Platform.runLater(() -> 
                            timeLabel.setText("时间: " + finalTime + "秒")
                        );
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    public static void main(String[] args) {
        launch(args);
    }
}